home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 007 / vtkerma1.arc / MSMENU.ASM < prev    next >
Assembly Source File  |  1986-02-13  |  27KB  |  1,050 lines

  1.     PAGE 59, 132
  2.  
  3.     TITLE MsMenu -- Dynamic menu generator for Kermit and descendents
  4.  
  5. ; Update 6 Jan 86
  6.  
  7. IF1
  8.  %OUT >> Starting pass 1
  9. ELSE
  10.  %OUT >> Starting pass 2
  11. ENDIF
  12.  
  13.     PUBLIC Menu, Quick_menu, Menu_file_name, Reload_menu_flag
  14.  
  15. ;***************************************************************************
  16. ; *Definitions* ...
  17.  
  18. ; Global defs
  19.  
  20.     INCLUDE MsDefs.H
  21.  
  22. Color_attr=30h            ; Black on Cyan
  23. Color_highlight=1Eh        ; Yellow on Blue
  24. Color_header_attr=74h        ; Red on White
  25.  
  26. Mono_attr=70h            ; Black on white
  27. Mono_highlight=07h        ; White on black
  28.  
  29. Upper_left=218            ; Box drawing chars
  30. Upper_right=191
  31. Lower_left=192
  32. Lower_right=217
  33. Horizontal=196
  34. Vertical=179
  35. Left_tee=180
  36. Right_tee=195
  37.  
  38. Screen    EQU 10h            ; BIOS screen call
  39. Kb    EQU 16h            ; BIOS keyboard call
  40.  
  41. Number_of_columns EQU 80    ; Width in characters
  42. Number_of_rows_PC EQU 25    ; Length in rows including mode line
  43. Number_of_chars_on_PC_screen EQU Number_of_columns*Number_of_rows_PC
  44.                 ; Number of chars in IBM screen
  45.  
  46. ; Flags in Screen_flags (in MSYIBM)
  47.  
  48. Screen_changed EQU 8        ; Data on more than one line changed
  49. Force_screen_update EQU 10h    ; Update every character of both video pages,
  50.                 ;  (on color card), which is slower than
  51.                 ;  mollasses in January
  52.  
  53. ; Scan codes for keys we have predefined ...
  54.  
  55. Escape_key EQU 1
  56. Space_key EQU 57
  57.  
  58. F6_key    EQU 64
  59. ALT_F6_key EQU 109
  60.  
  61. Left_key EQU 75
  62. Right_key EQU 77
  63.  
  64. Up_key EQU 72
  65. Down_key EQU 80
  66.  
  67. PgUp_key EQU 73
  68. PgDn_key EQU 81
  69.  
  70. Home_key EQU 71
  71. End_key    EQU 79
  72.  
  73. Return_key EQU 28
  74.  
  75. Seg_is_Alloc MACRO
  76.     call Use_our_own_ds
  77.     ASSUME ds:MAlloc, es:MAlloc
  78.     ENDM
  79.  
  80. Seg_is_Datas MACRO
  81.     call Back_to_normal_ds
  82.     ASSUME ds:DataS, es:DataS
  83.     ENDM
  84.  
  85. DataS    SEGMENT PUBLIC 'DataS'
  86.  
  87.     EXTRN Which_page:BYTE, Screen_flags:BYTE, Old_Image:WORD
  88.     EXTRN Video_page_addresses:WORD, m7171:BYTE, In_menu_mode:BYTE
  89.     EXTRN Force_mono:BYTE, m7171:BYTE, TakAdr:WORD, TakLev:BYTE
  90.  
  91. Menu_file_name LABEL BYTE
  92.     Program_name
  93.     DB '.MNU', 60 DUP (0)
  94.  
  95. Saved_mode_line DW Number_of_columns DUP (?) ; Saved image of Mode line
  96.  
  97. Characters LABEL BYTE
  98.     DB    Home_key,    End_key,    PgUp_key
  99.     DB    PgDn_key,    Up_key,        Down_key
  100.     DB    Left_key,    Right_key,    Return_key
  101. N_Characters EQU $-Characters
  102. Actions    LABEL WORD
  103.     DW     Do_Home,    Do_End,        Do_PgUp
  104.     DW    Do_PgDn,    Do_Up,        Do_Down
  105.     DW    Do_Up,        Do_Down,    Do_Return
  106.     DW    Do_other
  107.  
  108. No_memory DB '      ***  Not enough memory for MENU  --  Press any key to continue ***$'
  109.  
  110. Cr_str    DB Cr, '$'
  111.  
  112. Cant_find_file DB '        *****   Missing '
  113.     Program_name
  114.     DB '.MNU  --  Press any key to continue  *****$'
  115.  
  116. Ctrl_C_static_text DB 'Set Mode Command',0,0
  117. Ctrl_C_stext_len EQU $ - Ctrl_C_static_text
  118.  
  119. Reload_menu_flag DB 0        ; Flag that file needs reloading
  120.  
  121. DataS    ENDS
  122.  
  123.  
  124. ; Dummy segment for allocated memory
  125.  
  126. MAlloc    SEGMENT AT 0
  127.  
  128. Menu_items DW 20 DUP (?)    ; Ptrs to texts for menu item names
  129. Menu_data DW 20 DUP (?)        ; Ptrs to data for menu items
  130. Ctrl_C_ptr DW 1 DUP (?)        ; Ptr to ^C data line
  131. N_items    DW ?            ; The number of items in our list
  132.  
  133. File_handle DW ?        ; File handle for menu file
  134. Which_item DW ?            ; Item number we are on, from 0
  135. Last_item DW ?            ; Number of the last item
  136. Width_counter DW ?        ; Working counter of chars per line
  137. Item_width DW ?            ; Number of characters per item
  138. Header_ptr DW ?            ; OFFSET of Header text
  139. Header_length DW ?        ; Length of Header text
  140. Menu_window_top DW ?        ; Topmost row of menu
  141. Menu_window_left DW ?        ; Leftmost column of menu
  142. Full_keystroke DW ?        ; Scan code in high half, ASCII value in low
  143.  
  144. Which_line DW ?            ; Current line number on screen
  145.  
  146. Our_cursor DW ?            ; Our position
  147. Our_Image DW Number_of_chars_on_PC_screen DUP (?) ; Our buffer
  148.  
  149. Menu_database DB 100*74 DUP (?)    ; Where we store the Menu text
  150. Menu_file_buffer DB 2048 DUP (?) ; Buffer for reading Menu file from disk
  151.  
  152. Unhighlight DB ?        ; Normal attribute
  153. Highlight DB ?            ; Highlighted attribute
  154. Header_attribute DB ?        ; Header line attribute
  155. Ctrl_C_data DB 20 DUP (?)    ; Place to hold ^C text
  156.  
  157. End_MAlloc LABEL BYTE        ; Ptr to end of what we need
  158.  
  159. MAlloc    ENDS
  160.  
  161.  
  162. Code    SEGMENT PUBLIC
  163.  
  164.     EXTRN Put_Screen:NEAR, Get_Screen_Segment:NEAR, Boop:NEAR
  165.     EXTRN Which_card:BYTE, SPath:NEAR, Check_table:NEAR
  166.     EXTRN Get_memory_block:NEAR, PutErr_PC:NEAR, Screen_Image_ptr:DWORD
  167.     EXTRN Mode_line_ptr:DWORD, Comnd:NEAR, Go_to_page_zero:NEAR
  168.     EXTRN Save_command_mode_screen:NEAR, Restore_command_mode_screen:NEAR
  169.  
  170.     ASSUME CS:Code, DS:DataS, ES:DataS
  171.  
  172. Normal_ds DW ?            ; Ptr back to ds on entry
  173. MAlloc_ds DW ?            ; Address of MAlloc segment
  174.  
  175. MFlags    DB 0            ; Internal flags, kept in code segment
  176.                 ;  for easy access
  177.  
  178. Bye_bye EQU 1            ; Flag to leave
  179. Been_here EQU 2            ; Already did once-only initialization
  180. Newlin    EQU 4            ; We are at the start of a text line
  181. New_item EQU 8            ; We have seen an item but no data yet
  182. In_header EQU 10h        ; In a header definition
  183.  
  184. Menu    PROC
  185.  
  186.     mov ah, CmCfm
  187.     call Comnd        ; Get a confirm
  188.      jmp R
  189.  
  190. Quick_menu:
  191.     call Do_menu        ; Call routine to do the work
  192.      nop
  193.      nop
  194.      nop
  195.     jmp RSkp        ; We return skip no matter what
  196.  
  197. Do_menu:
  198.     and cs:MFlags, NOT Bye_bye    ; Flag that we aren't leaving yet
  199.  
  200.     test cs:MFlags, Been_here    ; Been here before?
  201.      jz MNU_go        ;  No ...
  202.  
  203. ; We have been here before, so we already have memory allocated ...
  204. ;  Do we need to reload the database?
  205.  
  206.     cmp Reload_menu_flag, 0    ; Is the flag to reload set?
  207.      jne MNU_reload        ;  Yes, reload it
  208.  
  209.     call Use_our_own_ds    ; Switch to Alloc segment
  210.     call Install_screen    ; Save, then blank the background
  211.     jmp SHORT MNU_1        ; Go use the database we already have set up
  212.  
  213. MNU_reload:
  214.     mov Reload_menu_flag, 0    ; Clear flag for next time
  215.     mov ax, MAlloc_ds    ; Reuse old memory
  216.     jmp SHORT H_ok        ; Join common code
  217.  
  218. MNU_go:
  219.  
  220. ; First, get some memory to work in
  221.  
  222. ; *** The silly assembler won't let me do this, saying
  223. ;    Constant was expected
  224. ;   SHR is an assembly-time operator according to the manual, so this
  225. ;    construct should be legit. 
  226. ;   Still a problem from IBM MASM 1.0 up to and including Microsoft MASM
  227. ;    version 4.0.  [tested jan 86] 
  228.  
  229. ;    mov bx, (OFFSET End_MAlloc+15) SHR 4 ; Lowest location we don't use,
  230.                 ;  round up to next higher paragraph,
  231.                 ;  then convert to number of paragraphs
  232.  
  233.     mov bx, OFFSET End_MAlloc+15 ; Round up to next paragraph
  234.     mov cl, 4        ; Shift count
  235.     shr bx, cl        ; Shift to get number of paras we need
  236.  
  237.     call Get_memory_block    ; Get a memory block of the right size
  238.      jnc H_OK        ;  Ok so far ...
  239.  
  240.     mov dx, OFFSET No_memory ; Complain
  241.     jmp Do_mode_line_error    ; Display noisy error message, wait for
  242.                 ;  keystroke, then exit, restoring
  243.                 ;  clobbered mode line
  244.  
  245. H_OK:    mov MAlloc_ds, ax    ; Save the address of our block
  246.  
  247.     mov bx, ds        ; Set up ptr back to ds
  248.     mov Normal_ds, bx    ; Save ptr back to old one
  249.     Seg_is_Alloc        ; Alloc segment
  250.     call Build_Menu_database ; Build the database
  251.     test cs:MFlags, Bye_bye    ; Time to leave?
  252.      jz MNU_0        ;  Not yet
  253.  
  254. ; *** Properly speaking, we really ought to release the memory we
  255. ;    were just allocated, since we can't use it ... maybe later ***
  256.  
  257.     jmp Back_to_normal_ds    ; Oh well ...
  258.  
  259.     ASSUME ds:MAlloc, es:MAlloc
  260. MNU_0:    or cs:MFlags, Been_here    ; Flag for later
  261.     call Install_screen    ; Set up to call Put_Screen
  262.     add Item_width, 2    ; Add in some padding for menu items
  263.  
  264.     mov ax, 78        ; Determine the number of spaces to the
  265.     sub ax, Item_width    ;  left of the menu
  266.     shr ax, 1        ; Divide leftover by two
  267.     mov Menu_window_left, ax ; Store the answer
  268.  
  269.     mov ax, 21        ; Count lines outside window
  270.     sub ax, N_items        ; Subtract for items (4 others preallocated)
  271.     shr ax, 1        ; Divide total rows by 2
  272.     mov Menu_window_top, ax    ; Store the answer
  273.  
  274. MNU_1:    call Build_menu_box    ; Build outline / background for Menu window
  275.  
  276.     call Fill_menu_frame    ; Put menu items and header in frame
  277.  
  278.     mov Which_item, 0    ; This is the one we want
  279.     call Highlight_line    ; Make it stand out
  280.  
  281. MNU_2:    call Do_the_screen    ; Display this frame
  282.  
  283.     call Check_keystrokes    ; See what to do next
  284.     test cs:MFlags, Bye_bye    ; Time to leave?
  285.      jz MNU_2        ;  No, go update the frame
  286.  
  287.     Seg_is_Datas        ; Datas segment
  288.     call Set_up_macro    ; Set up a macro to run when we get out
  289.     call Go_to_page_zero    ; Back to normal
  290.     jmp Restore_command_mode_screen
  291.  
  292.  
  293.     PUBLIC Set_up_macro
  294.  
  295. Set_up_macro:
  296.     mov ax, MAlloc_ds    ; MAlloc segment
  297.     mov ds, ax        ; Install in ds
  298.     ASSUME ds:MAlloc    
  299.     cld            ; Forwards
  300.     inc TakLev        ; Bump take level
  301.     add takadr, SIZE takinfo ; Address new take frame
  302.  
  303.     mov bx, Which_item    ; Item number that was selected
  304.     shl bx, 1        ; Double for word offset
  305.     mov si, Menu_data[bx]    ; Pick up pointer to data for this item
  306.  
  307.     mov bx, es:TakAdr    ; Get TAKE frame addr into bx
  308.     mov BYTE PTR es:[bx].TakFcb, 0FFh ; Mark as a macro
  309.  
  310.     lea di, es:[bx].TakBuf    ; Put it in the TAKE buffer
  311.     sub cx, cx        ; Clear counter
  312.  
  313. CPC_1:    lodsb            ; Get a byte
  314.     or al, al        ; Null?
  315.      jne CPC_3
  316.  
  317.     mov al, Cr        ; Load up a Cr for end-of-line
  318.     stosb            ; Store it
  319.     inc cx            ; Count this char
  320.  
  321.     lodsb            ; Is there another data line?
  322.     cmp al, "+"        ; Well?
  323.      jne CPC_4        ;  No, quit
  324.  
  325.     jmp CPC_1        ; Go do the next line of data
  326.  
  327. CPC_3:    stosb            ; Deposit char
  328.     inc cx            ; Count this char
  329.     or al, al        ; Hit end?
  330.      jne CPC_1        ;  No
  331.     
  332.     PUBLIC CPC_4, CPC_1, CPC_ret, CPC_3
  333.  
  334. CPC_4:    lea ax, es:[bx].takbuf    ; Pick up ptr to start of TAKE buffer
  335.     mov es:[bx].takptr, ax    ; Init buffer ptr
  336.     mov es:[bx].takchl, cl    ; Chars remaining
  337.     mov es:[bx].takcnt, cx    ;  and all chars
  338.     mov es:[bx].takcnt+2, 0    ; Clear high order half
  339.  
  340. CPC_ret:
  341.     mov ax, Normal_ds    ; DataS segment
  342.     mov ds, ax        ; Install in ds
  343.     ASSUME ds:DataS
  344.     ret            ; Done here
  345.  
  346. Bombed:    call Boop        ; Bombed, make a noise
  347.     or cs:MFlags, Bye_bye    ; Go home
  348.     ret
  349.  
  350.  
  351.     PUBLIC Build_Menu_database
  352.  
  353.     ASSUME ds:MAlloc, es:MAlloc
  354. Build_Menu_database:
  355.  
  356.     mov ax, Normal_ds    ; Switch ds to DataS
  357.     mov ds, ax
  358.     ASSUME ds:DataS
  359.  
  360.     mov si, OFFSET Ctrl_C_static_text ; Ptr to source
  361.     mov di, OFFSET Ctrl_C_data ; Ptr to target
  362.     cld            ; Forwards
  363.     mov cx, Ctrl_C_stext_len ; The number of bytes to copy
  364.     rep movsb        ; Copy the string
  365.  
  366.     mov ax, MAlloc_ds    ; Switch ds back to MAlloc
  367.     mov ds, ax
  368.     ASSUME ds:Malloc
  369.  
  370.     mov ax, OFFSET Ctrl_C_data ; Pick up ptr to control-C text
  371.     mov Ctrl_C_ptr, ax    ; Store it away for later
  372.  
  373.     mov N_items, 0        ; No items yet
  374.     mov Item_width, 0    ; This is the widest item seen so far
  375.     Seg_is_Datas        ; Datas segment
  376.     mov ax, OFFSET Menu_file_name ; Name of file to get
  377.     call spath        ; Search path for file, DSK: first
  378.      jnc BUI_ok        ;  Got it, go work with it
  379.  
  380.     mov dx, OFFSET Cant_find_file ; Complain
  381.     call Do_mode_line_error ; Wait for a key
  382.     jmp Use_our_own_ds    ; Reset ds and return NG
  383.  
  384. BUI_ok:    mov dx, ax        ; Copy ptr to name to dx
  385.     mov ax, (Open2*100h) + 0 ; Open file for input
  386.     int DOS            ; Try to open the file
  387.      jc Bombed        ;  Huh?
  388.  
  389.     Seg_is_Alloc        ; Alloc segment
  390.     mov File_handle, ax    ; Save file handle for later
  391.     mov di, OFFSET Menu_database ; Ptr to start of our database
  392.     cld            ; Build forwards
  393.     or MFlags, Newlin    ; We start on a new line
  394.  
  395. BUI_disk_read:
  396.     mov ah, ReadF2        ; Code to read from file
  397.     mov bx, File_handle    ; DOS file handle
  398.     mov cx, SIZE Menu_file_buffer ; Number of characters to try for
  399.     mov dx, OFFSET Menu_file_buffer ; Where to put them
  400.     int DOS            ; Read from the Menu file
  401.      jc BUI_finish        ;  Stop on error
  402.  
  403.     or ax, ax        ; Check for zero bytes read
  404.      jz BUI_finish        ; Hit EOF, go finish it up
  405.  
  406.     mov cx, ax        ; Byte count for this record
  407.     inc cx            ; We decr once too many times
  408.     mov si, OFFSET Menu_file_buffer ; Ptr to buffer
  409.  
  410. BUI_lp:    loop BUI_next_char    ; If more chars, go get one
  411.     jmp SHORT BUI_disk_read    ; Buffer is empty, try to refill it
  412.  
  413. BUI_next_char:
  414.     lodsb            ; Get the next byte
  415.  
  416.     cmp al, Space        ; In the control-char range?
  417.      jl BUI_control        ;  Yes, don't store it, check for linefeed
  418.  
  419.     stosb            ; Store the char
  420.     test MFlags, Newlin    ; At start of a line?
  421.      jz BUI_not_first_char    ;  No
  422.  
  423.     call BUI_do_first_char    ; Use routine to do it
  424.     jmp BUI_lp
  425.  
  426. BUI_not_first_char:
  427.     inc Width_counter    ; Track the size of each line
  428.     jmp Bui_lp        ; Go try for another char
  429.  
  430.  %OUT >> About half way through source file
  431.  
  432.  
  433. BUI_control:
  434.     cmp al, Lf        ; Line feed?
  435.      jne BUI_lp        ;  No
  436.  
  437.     or MFlags, Newlin    ; We are now on a new line
  438.     sub al, al        ; Make a zero
  439.     stosb            ; Tie off the last line
  440.  
  441.     test MFlags, New_item + In_header ; Was this an item or hdr line?
  442.      jz BUI_lp        ;  No
  443.  
  444.     mov ax, Width_counter    ; Pick up current width
  445.  
  446.     test MFlags, In_header    ; Header?
  447.      jz BUI_tag        ;  No
  448.  
  449.     mov Header_length, ax    ; Save length for header centering
  450.  
  451. BUI_tag:
  452.     cmp ax, Item_width    ; Compare with previous maximum
  453.      jle BUI_lp        ;  Not bigger
  454.  
  455.     mov Item_width, ax    ; Save this new maximum
  456.     jmp BUI_lp        ; Go get another character
  457.  
  458. BUI_finish:
  459.     mov ax, N_items        ; Count of items
  460.     dec ax            ; Drop by 1
  461.     mov Last_item, ax    ; Store as number of last item
  462.  
  463.     sub al, al        ; Make a zero
  464.     mov cx, 13        ; Make several blank lines after Menu database
  465.     rep stosb        ; Write a string of zeros
  466.  
  467.     mov ah, 3eh        ; Code to close a file
  468.     int DOS            ; Close the file
  469.  
  470.     ret            ; Done here
  471.  
  472. BUI_do_first_char:
  473.     and MFlags, NOT (Newlin + In_header) ; Turn off some flags
  474.     mov Width_counter, 0    ; Start line length counter to zero
  475.  
  476.     cmp al, "%"        ; Code for header?
  477.      jne DFC_not_hdr    ;  No
  478.  
  479.     mov Header_ptr, di    ; Store header pointer for later
  480.     or MFlags, In_header    ; We want special length tracking
  481.     jmp SHORT DFC_ret
  482.  
  483. DFC_Not_hdr:
  484.     cmp al, "*"        ; Code for item?
  485.      jne DFC_not_item    ;  No
  486.  
  487.     mov bx, N_items        ; Get pointer to the current row
  488.     shl bx, 1        ; Double for word offset
  489.     mov Menu_items[bx], di    ; Store pointer to the item
  490.  
  491.     inc N_items        ; This is a new item, add one to the count
  492.     or MFlags, New_item    ; Flag that we need a data pointer
  493.     jmp SHORT DFC_ret
  494.  
  495. DFC_Not_item:
  496.     cmp al, "+"        ; Code for data?
  497.      jne DFC_ret        ;  No
  498.  
  499.     test MFlags, New_item    ; Only store ptr to the first line of data
  500.      jz DFC_ret        ;  Ignore this one, ptr already set
  501.  
  502.     mov bx, N_items        ; Get pointer to the current row
  503.     dec bx            ; Pull back to previous row
  504.     shl bx, 1        ; Double for word offset
  505.     mov Menu_data[bx], di    ; Store pointer to the data
  506.     and MFlags, NOT New_item ; Clear flag for next time
  507.  
  508. DFC_ret:
  509.     ret            ; Done here
  510.  
  511.  
  512. Install_Screen:
  513.     Seg_is_Datas        ; Datas segment
  514.     call Save_command_mode_screen ; First, save what is already up there
  515.     Seg_is_Alloc        ; Alloc segment
  516.  
  517.     mov ax, 0720h        ; White blanks on black background
  518.     mov di, OFFSET Our_Image ; Ptr to our buffer
  519.     mov cx, Number_of_chars_on_PC_screen
  520.     cld            ; Forwards
  521.     rep stosw        ; Clear our buffer
  522.  
  523.     mov bx, OFFSET Our_Image ; Ptr to our buffer
  524.  
  525.     mov ax, Normal_ds    ; Use normal again
  526.     mov ds, ax        ; Install in ds
  527.     ASSUME ds:DataS
  528.  
  529.     or Screen_flags, Force_screen_update
  530.     call Put_Screen        ; Set up both video pages
  531.  
  532.     mov ax, MAlloc_ds    ; Use our own segment
  533.     mov ds, ax        ; Install in ds
  534.     ASSUME ds:MAlloc
  535.     ret
  536.  
  537.  
  538.     PUBLIC Build_menu_box
  539.  
  540. Build_menu_box:
  541.  
  542. ; Set up proper attribute based on card type
  543.  
  544.     mov ah, Mono_attr    ; Mono
  545.     mov Unhighlight, ah
  546.     mov ah, Mono_highlight
  547.     mov Highlight, ah
  548.     mov Header_attribute, ah
  549.  
  550.     Seg_is_Datas        ; Datas segment
  551.     cmp Force_mono, 0    ; Are we stuck with mono?
  552.      jne MON_0        ;  Yes
  553.  
  554.     call Get_Screen_Segment
  555.     cmp ax, 0b000h        ; Mono?
  556.      je MON_0        ;  It is, go use it
  557.  
  558.     Seg_is_Alloc        ; Alloc segment
  559.     mov ah, Color_attr    ; Color, use it instead
  560.     mov Unhighlight, ah
  561.     mov ah, Color_highlight
  562.     mov Highlight, ah
  563.     mov ah, Color_header_attr
  564.     mov Header_attribute, ah
  565.     jmp SHORT MON_1
  566.  
  567. MON_0:
  568.     Seg_is_Alloc        ; Alloc segment
  569.  
  570. MON_1:    mov ax, Menu_window_top    ; Row number of top of window
  571.     mov Which_line, ax    ; Save it for later
  572.     call Make_new_ptr    ; Get a new DI
  573.  
  574. ; Do top row of Menu window
  575.  
  576.     mov al, Upper_left    ; Graphic character for upper left corner
  577.     mov ah, Unhighlight    ; Attribute for no highlighting
  578.     stosw
  579.  
  580.     mov al, Horizontal
  581.     mov cx, Item_width
  582.     rep stosw
  583.  
  584.     mov al, Upper_right
  585.     stosw
  586.  
  587.     inc Which_line        ; Bump to next row
  588.     call Make_new_ptr    ; Point to it
  589.  
  590.     mov al, Vertical
  591.     stosw
  592.  
  593.     mov al, Space        ; Do the header line
  594.     mov ah, Header_attribute
  595.     mov cx, Item_width
  596.     rep stosw
  597.  
  598.     mov al, Vertical
  599.     mov ah, Unhighlight
  600.     stosw
  601.  
  602.     inc Which_line        ; Bump to next row
  603.     call Make_new_ptr    ; Point to it
  604.  
  605.     mov al, Right_tee
  606.     stosw
  607.  
  608.     mov al, Horizontal
  609.     mov cx, Item_width
  610.     rep stosw
  611.  
  612.     mov al, Left_tee
  613.     stosw
  614.  
  615.     inc Which_line        ; Bump to next row
  616.     call Make_new_ptr    ; Point to it
  617.  
  618.     mov cx, N_items        ; Do one line for each item
  619.  
  620. ; Do the middle rows of the Menu window
  621.  
  622. LP_1:    push cx
  623.  
  624.     mov al, Vertical
  625.     stosw
  626.  
  627.     mov al, Space
  628.     mov cx, Item_width
  629.     rep stosw
  630.  
  631.     mov al, Vertical
  632.     stosw
  633.  
  634.     pop cx
  635.  
  636.     inc Which_line        ; Bump to next row
  637.     call Make_new_ptr    ; Point to it
  638.  
  639.     loop LP_1
  640.  
  641. ; Do bottom row of Menu window
  642.  
  643.     mov al, Lower_left
  644.     stosw
  645.  
  646.     mov al, Horizontal
  647.     mov cx, Item_width
  648.     rep stosw
  649.  
  650.     mov al, Lower_right
  651.     stosw
  652.  
  653.     mov Our_cursor, (25*256)+0 ; Put cursor where it won't be seen
  654.     ret
  655.  
  656.  
  657. ; Make ptr to another item
  658.  
  659. New_line:
  660.     mov di, Which_item    ; Number of the menu item we are doing
  661.     add di, Menu_window_top    ; Adjust for top of list of menu items
  662.     add di, 3
  663.     mov Which_line, di    ; Set up as the line to work on
  664. ;    jmp Make_new_ptr    ; Make a new pointer to the line
  665.  
  666. ; Set up a pointer to this row
  667.  
  668. Make_new_ptr:
  669.     push ax            ; Save reg
  670.     push bx
  671.     mov ax, Which_line    ; Row number of topmost row
  672.     mov bh, 2 * Number_of_columns ; Convert to bytes 
  673.     mul bh
  674.  
  675.     add ax, Menu_window_left ; Account for columns to the left
  676.     add ax, Menu_window_left
  677.     add ax, OFFSET Our_Image ; Finally, add in the address of the buffer
  678.     mov di, ax        ; Set up as destination
  679.     pop bx
  680.     pop ax
  681.     ret            ; Go use it
  682.  
  683.     PUBLIC Fill_menu_frame
  684.  
  685. Fill_menu_frame:
  686.     mov ax, Menu_window_top    ; Row number to start writing to
  687.     inc ax            ; Bump it again
  688.     mov Which_line, ax    ; Save it
  689.     call Make_new_ptr    ; Get a new DI
  690.     add di, 2        ; Skip over border
  691.  
  692.     mov bx, Item_width    ; Pick up item width
  693.     sub bx, Header_length    ; Subtract length of header
  694. ; bx := bx / 2 for centering
  695. ; bx := bx * 2 for byte-to-word conversion
  696.     and bx, NOT 1        ; Force it EVEN
  697.  
  698.     add di, bx        ; Adjust ptr for Header centering
  699.  
  700. ; Do the header
  701.  
  702.     mov si, Header_ptr    ; Use the header text here
  703.  
  704. F00_lp_inner:
  705.     lodsb            ; Pick up the next byte
  706.     or al, al        ; Check for zero
  707.      jz F00_tag        ;  Hit end
  708.  
  709.     stosb            ; Store this char
  710.     inc di            ; Skip attribute
  711.     jmp F00_lp_inner    ; Go do another char
  712.  
  713. ; Do the items
  714.  
  715. F00_tag:
  716.     mov Which_item, 0    ; Start on item zero
  717.  
  718. FIL_lp_outer:
  719.     mov bx, Which_item    ; Item we are on
  720.     shl bx, 1        ; Double for word offset
  721.     mov si, Menu_items[bx]    ; Ptr to item text
  722.     call New_line        ; Set up di for this line
  723.     add di, 4        ; Skip over the border and one space
  724.  
  725. FIL_lp_inner:
  726.     lodsb            ; Pick up the next byte
  727.     or al, al        ; Check for zero
  728.      jz FIL_end_of_inner    ;  Hit end
  729.  
  730.     stosb            ; Store this char
  731.     inc di            ; Skip attribute
  732.     jmp FIL_lp_inner    ; Go do another char
  733.  
  734. ; End of inner loop, skip chars until we hit a zero byte
  735.  
  736. FIL_end_of_inner:
  737.     inc Which_item        ; Bump to next item
  738.     mov ax, Which_item    ; Get it in ax
  739.     cmp ax, Last_item    ; Over the hill?
  740.      jle FIL_keep_going
  741.  
  742.     ret            ; Done filling
  743.  
  744. FIL_keep_going:
  745.     inc Which_line        ; Move to next row
  746.     call Make_new_ptr    ; Get a new DI
  747.     add di, 4        ; Skip over border and first column
  748.  
  749.     jmp FIL_lp_outer    ; Go try for another line
  750.  
  751.     PUBLIC Do_other
  752.  
  753. Do_other:
  754.     Seg_is_Alloc        ; Alloc segment
  755.     cmp BYTE PTR Full_keystroke, 3 ; Was it a control-C?
  756.      jne DOT_0        ;  No
  757.  
  758.     mov Which_item, 20    ; Pretend item 20
  759.     jmp Do_return        ; Pretend selected
  760.  
  761. DOT_0:    mov bx, Which_item    ; The current item
  762.     mov Which_line, bx    ; Save it in another place
  763.  
  764.     mov ah, BYTE PTR Full_keystroke ; Pick up ASCII value of key user hit
  765.     cmp ah, 'a'        ; Compare with lower case 'a'
  766.      jb DOT_loop        ;  Too low
  767.     cmp ah, 'z'        ; Compare with lower case 'z'
  768.      ja DOT_loop        ;  Too high
  769.     sub ah, 32        ; Upcase this character
  770.  
  771. DOT_loop:
  772.     push bx            ; Save reg
  773.     shl bx, 1        ; Double for word offset
  774.     mov si, Menu_items[bx]    ; Get ptr to item text string
  775.     pop bx            ; Restore reg
  776.     lodsb            ; Get the first letter
  777.     cmp al, 'a'        ; Compare with lower case 'a'
  778.      jb DOT_No_upcase    ;  Too low
  779.     cmp al, 'z'        ; Compare with lower case 'z'
  780.      ja DOT_No_upcase    ;  Too high
  781.     sub al, 32        ; Upcase this character
  782.  
  783. DOT_No_upcase:
  784.     cmp al, ah        ; Do we have a winner?
  785.      jne No_match        ;  Not yet ...
  786.  
  787. ; Have a hit ...
  788.     push bx            ; Save new line
  789.     mov bx, Which_line    ; Get back ptr to old line
  790.     mov Which_item, bx    ; Set up for highlight routine
  791.     call Unhighlight_line    ; Unhiughlight the old line
  792.     pop WORD PTR Which_item    ; Get back new line
  793.     call Highlight_line    ; Highlight it
  794.     call Do_the_screen    ; Show these changes ...
  795.     jmp Do_return        ; Treat as if Return pressed while on this
  796.  
  797. No_match:
  798.     mov bx, Which_item    ; Item we are pointing to now
  799.     inc bx            ; Go up by 1
  800.     cmp bx, Last_item    ; Did we go too high?
  801.      jle No_prob        ;  No problem
  802.  
  803.     sub bx, bx        ; Move to the first item instead
  804.  
  805. No_prob:
  806.     mov Which_item, bx    ; Store the new item number
  807.     cmp bx, Which_line    ; Back to start?
  808.      je Do_boop        ;  Yeah, complain
  809.  
  810.     jmp DOT_loop        ; Go try the next one
  811.  
  812. Do_boop:
  813.     Seg_is_Datas        ; Datas segment
  814.     call Boop        ; Give low beep
  815.     Seg_is_Alloc        ; Alloc segment
  816. ;    jmp Check_keystrokes    ; Try again
  817.  
  818. Check_keystrokes:
  819.     mov ah, 1        ; Code to see if a char is ready
  820.     int Kb            ; Have BIOS tell us
  821.      jz Check_keystrokes    ;  None, waste time
  822.  
  823.     sub ah, ah        ; Zero is code to read the char
  824.     int Kb            ; Have BIOS get it for us
  825.  
  826.     mov Full_keystroke, ax    ; Save the whole thing here
  827.     Seg_is_Datas        ; Datas segment
  828.     mov al, ah        ; Copy scan code to al
  829.     mov bx, OFFSET Actions    ; Action table
  830.     mov cx, N_Characters    ; Number of scan codes to check
  831.     mov dx, OFFSET Characters ; The character table
  832.     jmp Check_Table        ; Go dispatch to the right routine
  833.  
  834.     ASSUME ds:Malloc, es:MAlloc
  835.  
  836. Do_the_screen:
  837.     mov bx, OFFSET Our_Image ; Set ptr to our screen
  838.  
  839.     mov ax, Normal_ds    ; Put_Screen likes normal ds
  840.     mov ds, ax
  841.     ASSUME ds:DataS
  842.  
  843.     or Screen_flags, Screen_changed ; Flag that Put_Screen has to work
  844.     call Put_Screen        ; Update screen
  845.  
  846.     mov ax, es        ; Copy es ...
  847.     mov ds, ax        ;  ... to ds
  848.     ASSUME ds:MAlloc
  849.  
  850.     ret            ; Done here
  851.  
  852. Move_highlight_up:
  853.     Seg_is_Alloc        ; Alloc segment
  854.     call Unhighlight_line
  855.     call Move_up
  856.     jmp Highlight_line
  857.  
  858. Move_highlight_down:
  859.     Seg_is_Alloc        ; Alloc segment
  860.     call Unhighlight_line
  861.     call Move_down
  862.     jmp Highlight_line
  863.  
  864. Do_Home:
  865.     Seg_is_Alloc        ; Alloc segment
  866.     call Unhighlight_line
  867.     mov Which_item, 0    ; Item 0
  868.     jmp Highlight_line
  869.     
  870. Do_End:
  871.     Seg_is_Alloc        ; Alloc segment
  872.     call Unhighlight_line
  873.     mov ax, Last_item    ; Final item on menu
  874.     mov Which_item, ax
  875.     jmp Highlight_line
  876.  
  877. Do_PgUp:
  878.     jmp Do_Home
  879.  
  880. Do_PgDn:
  881.     jmp Do_End
  882.  
  883. Do_Up:
  884.     jmp Move_highlight_up
  885.  
  886. Do_Down:
  887.     jmp Move_highlight_down
  888.  
  889. Do_return:
  890. ;    jmp CHK_bye
  891.  
  892. CHK_bye:
  893.     Seg_is_Alloc        ; Alloc segment
  894.     or cs:MFlags, Bye_bye    ; Flag the exit
  895.     ret            ; Done here
  896.  
  897. Highlight_line:
  898.     mov al, Highlight    ; Set up to highlight the chars
  899.     jmp SHORT Change_highlighting
  900.  
  901. Unhighlight_line:
  902.     mov al, Unhighlight    ; Set up to unhighlight the chars
  903. ;    jmp Change_highlighting
  904.  
  905. Change_highlighting:
  906.     call New_line
  907.     add di, 3        ; Skip over border, point at attribute
  908.     Seg_is_Alloc        ; Alloc segment
  909.     mov cx, Item_width    ; The number of attributes to hit
  910.  
  911. HIL_lp:    stosb
  912.     inc di
  913.     loop HIL_lp        ; Try for another
  914.     ret
  915.  
  916. Move_up:
  917.     mov ax, Which_item    ; Item we arte pointing to now
  918.     dec ax            ; Go up by 1
  919.     or ax, ax        ; See if negative
  920.      jns Move_is_OK        ;  No problem
  921.  
  922.     mov ax, Last_item    ; Move to the last item instead
  923.     jmp SHORT Move_is_OK
  924.  
  925. Move_down:
  926.     mov ax, Which_item    ; Item we are pointing to now
  927.     inc ax            ; Go up by 1
  928.     cmp ax, Last_item    ; Did we go too high?
  929.      jle Move_is_OK        ;  No problem
  930.  
  931.     sub ax, ax        ; Move to the first item instead
  932.  
  933. Move_is_OK:
  934.     mov Which_item, ax    ; Store the new item number
  935.     ret            ; That's it
  936.  
  937. Back_to_normal_ds:
  938.     push ax            ; Save reg
  939.     mov ax, Normal_ds    ; Pick up addr of DataS segment
  940.     mov ds, ax        ; Copy to ds
  941.      nop
  942.     mov es, ax        ;  and es
  943.     pop ax            ; Restore reg
  944.     ret            ;  and return
  945.  
  946.     ASSUME ds:DataS, es:DataS
  947.  
  948. Use_our_own_ds:
  949.     push ax            ; Save reg
  950.     mov ax, MAlloc_ds    ; Pick up addr of MAlloc segment
  951.     mov ds, ax        ; Copy to ds
  952.      nop
  953.     mov es, ax        ;  and es
  954.     pop ax            ; Restore reg
  955.     ret            ;  and return
  956.  
  957. Menu    ENDP
  958.  
  959. Do_mode_line_error PROC
  960.  
  961.     mov In_menu_mode, 0    ; Leave menu mode, if in it
  962.     call Save_mode_line    ; Ask for a save
  963.     call PutErr_PC        ; Play with mode line
  964.     call Bombed        ; Make noise
  965.     sub ah, ah        ; Code to read a character
  966.     int Kb            ; Wait until user hits key
  967.     call Restore_mode_line    ; Ask for a restore
  968.     mov ah, PrStr        ; Code to type a string
  969.     mov dx, OFFSET Cr_str    ; Simple carriage return
  970.     int Dos            ; Type it (force left margin)
  971.     ret            ; Done here
  972.  
  973. Do_mode_line_error ENDP
  974.  
  975.  
  976. ; Save the mode line for later restoral
  977.  
  978. Save_mode_line PROC
  979.  
  980.     push ds            ; Save ds
  981.     call Get_address    ; Get new ds into ax
  982.     mov ds, ax        ; Store the new seg addr
  983.     mov si, (Number_of_rows_PC-1)*2*Number_of_columns ; Offset of line 25
  984.     mov di, OFFSET Saved_mode_line ; Where to copy it
  985.     mov cx, Number_of_columns
  986.     cld            ; Forwards
  987.     rep movsw        ; Save the line
  988.     pop ds            ; Restore ds
  989.     ret
  990.  
  991. Save_mode_line ENDP
  992.  
  993.  
  994. ; Restore the mode line
  995.  
  996. Restore_mode_line PROC
  997.  
  998.     push es            ; Save es
  999.     call Get_address    ; Get new es into ax
  1000.     mov es, ax        ; Store the new seg addr
  1001.     mov si, OFFSET Saved_mode_line ; Where copy is
  1002.     mov di, (Number_of_rows_PC-1)*2*Number_of_columns ; Offset of line 25
  1003.     mov cx, Number_of_columns
  1004.     rep movsw        ; Restore the line
  1005.     pop es            ; Restore es
  1006.     ret
  1007.  
  1008. Restore_mode_line ENDP
  1009.  
  1010.  
  1011. ; Get address of segment of currently-displayed video page
  1012.  
  1013. Get_address PROC
  1014.  
  1015.     mov ax, 0B000h        ; Mono, maybe
  1016.     cmp Which_card, 0     ; Is it?
  1017.      je Go_back        ;  Yes
  1018.  
  1019.     sub bh, bh        ; Zero high half of bx
  1020.     mov bl, Which_page    ; The page we are on in the color card
  1021.     shl bx, 1        ; Double for word offset into table
  1022.     mov ax, Video_page_addresses[bx] ; Pick up the address for the page
  1023.  
  1024. Go_back:
  1025.     ret
  1026.  
  1027. Get_address ENDP
  1028.  
  1029. ; Jumping to this location is like retskp.  It assumes the instruction
  1030. ;   after the call is a jmp addr.
  1031.  
  1032. RSKP    PROC
  1033.     pop bp
  1034.     add bp,3
  1035.     push bp
  1036.     ret
  1037.  
  1038. RSKP    ENDP
  1039.  
  1040. ; Jumping here is the same as a ret
  1041.  
  1042. R    PROC
  1043.     ret
  1044. R    ENDP
  1045.  
  1046. Code    ENDS
  1047.  
  1048.     END
  1049. 
  1050.